package cn.singno.bob.jpa.annotation.core;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.singno.bob.common.utils.ReflectionUtils;
import cn.singno.bob.jpa.annotation.search.Result;
import cn.singno.bob.jpa.annotation.search.Search;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class JPASearchFilter implements SearchFilter{

	
	private static Logger logger = LoggerFactory.getLogger(JPASearchFilter.class);
	
	/**
	 * <p>名称：SearchFilterType.java</p>
	 * <p>描述：注解类型</p>
	 * <pre>
	 *    
	 * </pre>
	 * @author 鲍建明
	 * @date 2014年8月14日 下午1:12:16
	 * @version 1.0.0
	 */
	public enum SearchFilterType{
		/**
		 * 搜索
		 */
		SEARCH, 
		/**
		 * 排序
		 */
		ORDERBY;
	}
	
	public JPASearchFilter (){
		
	}
	
	/**
	 * 查询需要被返回的参数字段
	 */
	private List<Object> fields =  Lists.newLinkedList();
	
	/**
	 * 条件对象集合
	 */
	private List<SearchFilterBean> result = Lists.newLinkedList();

	/**
	 * 注解类型
	 */
	private SearchFilterType type;
	
	/**
	 * 查询对象
	 */
	private Object bean;
	
	/**
	 * 字段
	 */
	private Field field;
	

	public List<Object> getFields() {
		return fields;
	}
	/**
	 * 
	 * <p>描述：添加条件对象</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param bean
	 */
	private void addBean(SearchFilterBean bean){
		this.result.add(bean);
	}
	

	@Override
	public SearchFilter parseBean(Object searchBean) {
		this.bean = searchBean;
		if(this.bean == null){
			return this;
		}
		parseClass();
		parseField();
		return this;
	}
	
	/**
	 * 
	 * <p>描述：解析类中的字段</p>
	 * <pre>
	 *    
	 * </pre>
	 */
	private void parseField(){
		Field[] fields = getBean().getClass().getDeclaredFields();
		for (Field field : fields) {
			Annotation annotation = findAnnotation(field);
			if(annotation != null){
				this.field = field;
				changeAnnotation( annotation, getType());
			}
		}
	}
	
	/**
	 * 
	 * <p>描述：解析类上的返回参数</p>
	 * <pre>
	 *    
	 * </pre>
	 */
	private void parseClass(){
		Annotation annotation = getBean().getClass().getAnnotation(Result.class);
		Map<String, List<Object>> map = getAnnotationAttributes(annotation);
		if(MapUtils.isNotEmpty(map)){
			this.fields =  map.values().iterator().next();
		}
	}
	
	
	/**
	 * 
	 * <p>描述：只获取有值的注解参数和名称</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param annotation
	 * @return
	 */
	public Map<String, List<Object>> getAnnotationAttributes(Annotation annotation){
		Map<String, List<Object>> attr = Maps.newHashMap();
		if(annotation == null){
			return attr;
		}
		Method[] methods = annotation.annotationType().getDeclaredMethods();
		try {
			for (Method method : methods) {
				if (method.getParameterTypes().length == 0 && method.getReturnType() != void.class) {
					Object obj = method.invoke(annotation);
					List<Object> list = filterParam(obj);
					if(CollectionUtils.isNotEmpty(list)){
						attr.put(method.getName(), list);
					}
				}
				
			}
		}catch (Exception e) {
			e.printStackTrace();
			throw new IllegalStateException("Could not obtain annotation attribute values", e);	
		}
		return attr;
	}
	
	
	/**
	 * 
	 * <p>描述：查询指定的注解类型</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param annotation
	 * @param defaultVlaue  正确的注解类型
	 * @return
	 */
	public Annotation findAnnotation(Field field){
		for ( Annotation annotation : field.getAnnotations()) {
			Class<?> clazz = annotation.annotationType();
			if( clazz == Search.class){					//搜索
				setType(SearchFilterType.SEARCH);
				return annotation;		
			}
		}
		return null;
	}
	
	
	/**
	 * 
	 * <p>描述：选择注解类型进行不同的处理</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param field
	 * @param annotation
	 * @param type
	 * @return
	 */
	public void changeAnnotation( Annotation annotation, SearchFilterType type){
		
		switch (type) {
		case SEARCH:
			Map<String, List<Object>> map = getAnnotationAttributes(annotation);
			setSearchFilterBean(map, 1);
			break;
		default:
			break;
		}
	}
	
	
	
	/**
	 * 
	 * <p>描述：设置搜索Bean对象的动态参数</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param map
	 * @param field
	 * @return
	 */
	public  void setSearchFilterBean(Map<String, List<Object>> map, int annotationType) {
		for (Iterator<Entry<String, List<Object>>> it = map.entrySet().iterator(); it.hasNext(); ) {
			Entry<String, List<Object>> entry = it.next();
			switch (annotationType) {
			case 0:								//类上的注解
				break;
			case 1:								//Field上的注解
				parseExpression(this.field, entry.getKey(), entry.getValue() ); 
				break;
			default:
				break;
			}
		}
		
		
	} 
	
	/**
	 * 
	 * <p>描述：过滤参数是否有空值</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param objs
	 * @return
	 */
	public List<Object> filterParam(Object obj){
		List<Object> list = Lists.newArrayList();
		if(obj instanceof String){					
			if( StringUtils.isNotBlank(obj.toString()) ){
				list.add(obj);
			}
		}else if(obj instanceof String[]){			//数组类型转换
			String[] strs = (String[])obj;
			boolean flag = true;
			List<Object> list2 = Lists.newArrayList();
			for (String str : strs) {
				if(StringUtils.isBlank(str)){
					flag = false;
					break;
				}else{
					list2.add(str);
				}
			}
			if( flag ){
				list.addAll(list2);
			}
		}else{
			if(obj != null){
				list.add(obj);
			}
		}
		return list;
	}
	
	
	/**
	 * 
	 * <p>描述：解析注解上的表达式</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param annotationName    注解参数名
	 * @param annotationValue   注解参数值
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws NoSuchMethodException 
	 */
	public  void parseExpression(Field field, String annotationName, List<Object> annotationValue) {
		
		SearchOperator operator = null;
		switch (SearchOperator.getSearchOperator(annotationName)) {
		case EQ:
			operator = SearchOperator.EQ;
			break;
		case LIKE:
			operator = SearchOperator.LIKE;
			break;
		case GREATER:
			operator = SearchOperator.GREATER;
			break;
		case GREATER_EQ:
			operator = SearchOperator.GREATER_EQ;
			break;
		case IN:
			operator = SearchOperator.IN;
			break;
		case LESS:
			operator = SearchOperator.LESS;
			break;
		case LESS_EQ:
			operator = SearchOperator.LESS_EQ;
			break;
		case BETWEEN_AND:
			operator = SearchOperator.BETWEEN_AND;
			break;
		case ORDERBY:
			operator = SearchOperator.ORDERBY;
			break;
		default:
			throw new IllegalArgumentException("该注解没有这种类型的标示");
		}
		List<Object> result = parseResult(annotationValue, field);
		if(CollectionUtils.isNotEmpty(result)){
			addBean(new SearchFilterBean(field.getName(),operator, result));
		}
		
	}
	
	/**
	 * 
	 * <p>描述：解析注解中的表达式语句</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param annotationValue
	 * @param field
	 * @return
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public  List<Object> parseResult(List<Object> annotationValue, Field field) {
		List<Object> result = Lists.newLinkedList();
		for (Object obj : annotationValue) {
			Object res = parseObject(obj, field);
			if(res != null){
				result.add(res);
			}
		}
		return result;
	}

	public List<SearchFilterBean> getResult() {
		return result;
	}
	
	public SearchFilterType getType() {
		return type;
	}

	public void setType(SearchFilterType type) {
		this.type = type;
	}

	
	public Object getBean() {
		return bean;
	}

	public void setBean(Object bean) {
		this.bean = bean;
	}
	
	// 使用表达式语言是使用
	public Object parseObject(Object annotationValue, Field field) {

		if (annotationValue instanceof String) {
			return parseExpression((String) annotationValue, field);
		} else {
			return null;
		}
	}
	
	//表达式解析入口 
	private Object parseExpression(String annotationValue, Field field) {
		if (annotationValue.contains("#")) { // 取本身属性，调用get方法
			return ReflectionUtils.invokeGetterMethod(this.bean, field.getName());
			//return parseMy(annotationValue, field, true);
		} else if (annotationValue.contains("$")) { // 反射取值
			return parse$(annotationValue, field);
		}
		return annotationValue;
	}
	
	//#表达式解析
	private Object parse_(String fieldName){
		try{
			return ReflectionUtils.invokeGetterMethod(this.bean, fieldName);
		}catch(Exception e){
			return ReflectionUtils.getFieldValue(this.bean, fieldName);
		}
	}
	
	//$表达式解析
	@SuppressWarnings("rawtypes")
	private Object parse$(String annotationValue, Field field) {
		// 解析表达式
		String expression = filterExpression(annotationValue, "{", "}");
		String methodParams = findParam(expression);
		expression = expression.replace(methodParams, "");
		
		String[] params = expression.split("\\.");

		if (ArrayUtils.isEmpty(params)) { // 表达式为空
			throw new IllegalArgumentException("expression is null");
		} else if (params.length == 1) { // 只有一个时，取本身属性
			return parse_(params[0]);
		}

		
		Class clazz = parseClassPath(params);
		String lastParam = params[params.length - 1];
		int first = lastParam.indexOf("(");
		if (first != -1) { 						// 方法调用 格式 com.my.AppConstant.getMe()

			String methodName = lastParam.substring(0, first);
			//String methodParams = lastParam.substring(first + 1, last);
			return parseMethod(methodName, methodParams, clazz, field);
		} else { 								// 直接获取类中的字段 格式 com.my.AppConstant.DEL_TRUE
			return parseClassField(lastParam, clazz);
		}
	}
	
	/**
	 * 
	 * <p>描述：查询()中的参数</p>
	 * <pre>
	 *    
	 * </pre>
	 * @param str
	 * @return
	 */
	private String findParam(String str){
		Pattern p = Pattern.compile("(?<=\\()[^\\)]+");
		Matcher m = p.matcher(str);
		while(m.find()){
			return m.group().trim();				//这里只解析括号中一次表达式
		}
		return "";					
	}
	
	  
	  /**
	   * 
	   * <p>描述：</p>
	   * <pre>
	   *   过滤表达式 
	   * </pre>
	   * @param resouceStr
	   * @param prefix
	   * @param suffix
	   * @return
	   */
	  private String filterExpression(String resouceStr, String prefix, String suffix){
		 return resouceStr.replaceAll("^.*\\" + prefix, "").replaceAll(suffix + ".*", "").trim();
	  }
	  
	  /**
	   * 
	   * <p>描述：解析方法</p>
	   * <pre>
	   *    
	   * </pre>
	   * @param methodName
	   * @param methodParams
	   * @param clazz
	   * @return
	   */
	@SuppressWarnings("rawtypes")
	private Object parseMethod(String methodName, String methodParams,
			Class clazz, Field field) {
		Object[] args = parseMethodParams(methodParams, field);
		if (args == null) {
			return ReflectionUtils.invokeMeth(args, clazz, methodName);
		} else {
			List<Class<?>> types = Lists.newArrayList();
			for (Object object : args) {
				types.add(object.getClass());
			}
			return ReflectionUtils.invokeMethod(clazz, methodName, args,
					types.toArray(new Class[] {}));
		}
	}
	  
	  /**
	   * 
	   * <p>描述：解析方法里面的</p>
	   * <pre>
	   *    
	   * </pre>
	   * @param methodParams
	   * @return
	   */
	  private Object[] parseMethodParams(String methodParams, Field field){
		  if(StringUtils.isBlank(methodParams)){			//方法里面没有参数
			  return null;
		  }else{
			  List<Object> result = Lists.newArrayList();
			  String[] params = methodParams.split(",");
			  for (String str : params) {
				  if(str.contains("'")){
					  String param = str.replace("'", "");
					  result.add(param);
				  }else{
					  Object obj = parse$(str, field);
					  result.add(obj);
				  }
			  }
			  return result.toArray();
		  }
	  }
	  
	  /**
	   * 
	   * <p>描述：URL 转换类</p>
	   * <pre>
	   *    
	   * </pre>
	   * @param params
	   * @return
	   */
	  @SuppressWarnings("rawtypes")
	private Class parseClassPath(String[] params) {
		  StringBuffer classUrl = new StringBuffer();
		  for (int i = 0; i < params.length; i++) {
			  if (i == (params.length - 1)) {
				  break;
			  }
			  classUrl.append(params[i] + ".");
		  }
		  classUrl.deleteCharAt(classUrl.length() - 1);
		  try {
			  return ClassUtils.getClass(classUrl.toString());
		  } catch (ClassNotFoundException e) {
			  logger.error(e.getMessage());
			  throw new RuntimeException("class not found [" + classUrl.toString() + "]");
		  }
	  }
	  
	  /**
	   * 
	   * <p>描述：解析自身属性</p>
	   * <pre>
	   *    #{id}
	   * </pre>
	   * @param annotationValue
	   * @param field
	   * @return
	   */
	  private  Object parseMy(String annotationValue, Field field){
		  String fieldName = filterExpression(annotationValue, "{", "}");
		  return ReflectionUtils.invokeGetterMethod(this.bean, fieldName);
	  }
	  
	  /**
	   * 
	   * <p>描述：解析外部类的字段属性</p>
	   * <pre>
	   *     直接获取类中的字段 格式   ${com.my.AppConstant.DEL_TRUE}
	   * </pre>
	   * @param lastParam
	   * @param params
	   * @return
	   */
	  @SuppressWarnings("rawtypes")
	  private  Object parseClassField(String fieldName, Class clazz){
		return  ReflectionUtils.getFieldValue(clazz, fieldName);
	  }
}
